using System;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Network;

namespace OracleInternal.TTC
{
	internal class OraBufWriter
	{
		private MarshallingEngine m_marshallingEngine;

		private WriterStream m_writerStream;

		private byte[] m_oneByteBuffer = new byte[1];

		internal OracleCommunication m_oracleComm;

		internal OraBuf m_currentOB;

		internal byte[] m_currentObBuffer;

		internal int m_positionInCurrentOB;

		internal int m_startIdxForDataSegment;

		internal int m_lengthForDataSegment;

		internal OraBufWriter(MarshallingEngine mEngine, WriterStream writerStream, OracleCommunication oracleComm)
		{
			m_marshallingEngine = mEngine;
			m_writerStream = writerStream;
			m_oracleComm = oracleComm;
			Initialize();
		}

		internal void Initialize()
		{
			if (m_currentOB == null)
			{
				m_currentOB = m_oracleComm.OraBufPool.Get(m_oracleComm.SDU, m_oracleComm, bReceive: false);
			}
			else
			{
				m_currentOB.ReInit(forReceive: false);
			}
			m_currentObBuffer = m_currentOB.buf;
			m_startIdxForDataSegment = (m_positionInCurrentOB = m_currentOB.cursor);
			m_lengthForDataSegment = 0;
		}

		internal void Write(byte val)
		{
			if (m_currentOB.Space - m_positionInCurrentOB > 0)
			{
				m_currentObBuffer[m_positionInCurrentOB++] = val;
				m_lengthForDataSegment++;
			}
			else
			{
				m_oneByteBuffer[0] = val;
				Write(m_oneByteBuffer, 0, 1);
			}
		}

		internal void Write(byte[] inputBuffer)
		{
			Write(inputBuffer, 0, inputBuffer.Length);
		}

		internal void Write(byte[] inputBuffer, int offset, int length)
		{
			WriteDataToOraBuf(inputBuffer, offset, length);
		}

		internal void WriteLengthAndDataToOraBuf(bool bWritePrefixLength, int prefixLength, byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			bool flag = false;
			if (m_currentOB.Space - m_positionInCurrentOB > 0 && bWritePrefixLength)
			{
				m_currentObBuffer[m_positionInCurrentOB++] = (byte)((uint)prefixLength & 0xFFu);
				m_lengthForDataSegment++;
				flag = true;
			}
			while (true)
			{
				int num2 = m_currentOB.Space - m_positionInCurrentOB;
				if (num2 > 0)
				{
					num = ((length <= num2) ? length : num2);
					Buffer.BlockCopy(userBuffer, offset, m_currentObBuffer, m_positionInCurrentOB, num);
					m_positionInCurrentOB += num;
					m_lengthForDataSegment += num;
					length -= num;
					if (length == 0)
					{
						break;
					}
					offset += num;
				}
				else
				{
					FlushData();
					if (bWritePrefixLength && !flag)
					{
						m_currentObBuffer[m_positionInCurrentOB++] = (byte)((uint)prefixLength & 0xFFu);
						m_lengthForDataSegment++;
						flag = true;
					}
				}
			}
		}

		internal int WriteDataToOraBuf(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			int num2 = 0;
			while (true)
			{
				int num3 = m_currentOB.Space - m_positionInCurrentOB;
				if (num3 > 0)
				{
					num = ((length <= num3) ? length : num3);
					Buffer.BlockCopy(userBuffer, offset, m_currentObBuffer, m_positionInCurrentOB, num);
					m_positionInCurrentOB += num;
					num2 += num;
					m_lengthForDataSegment += num;
					length -= num;
					if (length == 0)
					{
						break;
					}
					offset += num;
				}
				else
				{
					FlushData();
				}
			}
			return num2;
		}

		internal void FlushData()
		{
			try
			{
				if (m_currentOB != null)
				{
					m_currentOB.Add(m_currentObBuffer, m_startIdxForDataSegment, m_lengthForDataSegment);
					m_writerStream.Write(m_currentOB);
				}
			}
			catch (NetworkException ex)
			{
				if (ex.ErrorCode != 3111)
				{
					throw;
				}
				Initialize();
				m_marshallingEngine.ProcessReset();
				if (m_marshallingEngine.TTCErrorObject.ErrorCode != 0)
				{
					byte[] errorMessage = m_marshallingEngine.TTCErrorObject.ErrorMessage;
					throw new OracleException(m_marshallingEngine.TTCErrorObject.ErrorCode, string.Empty, string.Empty, m_marshallingEngine.m_dbCharSetConv.ConvertBytesToString(errorMessage, 0, errorMessage.Length));
				}
			}
			finally
			{
				Initialize();
			}
		}
	}
}
